<template>
    <!-- 定义一个 Element Plus 的对话框组件，用于展示订单录入界面 -->
    <el-dialog v-model="addOrderUseOCRVisible" draggable :show-close="false" :close-on-click-modal="false" fullscreen destroy-on-close>
        <!-- 自定义对话框头部 -->
        <template #header="{ close, titleId, titleClass }">
            <div class="my-header">
                <!-- 显示对话框标题 -->
                <h4 :id="titleId" :class="titleClass">录入订单</h4>
                <!-- 关闭对话框按钮 -->
                <el-button type="danger" :icon="CircleCloseFilled" @click="close"> 关闭 </el-button>
            </div>
        </template>

        <!-- 上传内容区域 -->
        <div v-loading="ocrLoading" v-if="ocrResult.length == 0" class="paste-area">
            <!-- 提示用户支持粘贴图片或上传图片/PDF -->
            <p class="paste-tip">支持使用 Ctrl + V 粘贴图片 或 点击下面按钮上传图片/PDF</p>
            <!-- 文件上传输入框，隐藏显示，支持图片和 PDF 格式 -->
            <input type="file" accept="image/*, application/pdf" @change="handleFileUpload" hidden ref="fileInput" />
            <!-- 触发文件选择对话框的按钮 -->
            <el-button type="primary" @click="openFileDialog">上传图片/PDF</el-button>
            <!-- 预览区域，根据文件类型显示图片或 PDF 预览 -->
            <div v-if="previewImage || previewPDF" class="preview-container">
                <!-- 图片预览 -->
                <img v-if="previewImage" :src="previewImage" alt="预览图片" class="preview-image" />
                <!-- PDF 预览 -->
                <embed v-if="previewPDF" :src="previewPDF" type="application/pdf" width="100%" height="200px" />
                <!-- 显示 PDF 文件的页数 -->
                <p v-if="pdfPageCount" class="pdf-page-count">PDF 页数: {{ pdfPageCount }}</p>
                <!-- 确认上传按钮 -->
                <el-button type="primary" @click="uploadImage">确认上传</el-button>
                <!-- 清除预览按钮 -->
                <el-button type="danger" @click="clearPreview">清除预览</el-button>
            </div>
        </div>

        <!-- 表格操作选项区域 -->
        <div v-loading="createLoading" v-if="ocrResult.length > 0" class="table-options">
            <el-button @click="processSelectedData('productName')">设置产品名称列</el-button>
            <el-button @click="processSelectedData('orderNumber')">设置数量列</el-button>
            <el-button @click="processSelectedData('excludTaxPrice')">设置单价列（不含税）</el-button>
            <el-button @click="processSelectedData('includeTaxPrice')">设置单价列（含税）</el-button>
            <el-input style="padding: 0 12px" v-model="orderNo" placeholder="请输入订单号" clearable></el-input>
            <el-button @click="createOrderEvent">创建订单</el-button>
        </div>

        <div class="show-selected-area" v-if="ocrResult.length > 0">
            <table>
                <thead>
                    <tr>
                        <th>产品名称</th>
                        <th>数量</th>
                        <th v-if="uploadExcludTaxPriceData.length !== 0">单价（不含税）</th>
                        <th v-if="uploadIncludeTaxPriceData.length !== 0">单价（含税）</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="(item, index) in uploadProductNameData" :key="index">
                        <td>{{ item }}</td>
                        <td>{{ uploadOrderNumberData[index] }}</td>
                        <td v-if="uploadExcludTaxPriceData.length !== 0">{{ uploadExcludTaxPriceData[index] }}</td>
                        <td v-if="uploadIncludeTaxPriceData.length !== 0">{{ uploadIncludeTaxPriceData[index] }}</td>
                    </tr>
                </tbody>
            </table>
        </div>

        <!-- 展示 OCR 识别后的表格内容 -->
        <div class="ocr-area">
            <div class="table-content">
                <!-- 遍历 OCR 识别结果，每个结果代表一个页面 -->
                <div v-for="(page, pageIndex) in ocrResult" :key="pageIndex">
                    <h3>第 {{ pageIndex + 1 }} 页</h3>
                    <!-- 遍历每个页面中的表格 -->
                    <table v-for="(tableResult, tableIndex) in page.tables_result" :key="tableIndex">
                        <tbody>
                            <!-- 动态生成表格行 -->
                            <tr v-for="(row, rowIndex) in getRows(tableResult.body)" :key="rowIndex">
                                <!-- 动态生成表格单元格，支持框选操作 -->
                                <td
                                    v-for="(cell, cellIndex) in row.cells"
                                    :key="cellIndex"
                                    :colspan="cell.colSpan"
                                    :rowspan="cell.rowSpan"
                                    :data-nanoid="cell.nanoid"
                                    @mousedown="startSelection"
                                    @mouseover="updateSelection"
                                    @mouseup="endSelection"
                                    :class="{ 'selected-cell': selectedData.some((item) => item.nanoid === cell.nanoid) }"
                                >
                                    {{ cell.words }}
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </el-dialog>
</template>

<script setup lang="ts">
import { CircleCloseFilled } from '@element-plus/icons-vue';
import { getOCR } from '@/api/openPlatform/index.ts';
import { getAllProductList } from '@/api/product';
import * as pdfjs from 'pdfjs-dist';
import { createOrder } from '@/api/order';
import { useUserStore } from '@/store/modules/user';

// 组件挂载时，添加粘贴事件监听器
onMounted(() => {
    window.addEventListener('paste', handlePaste);
    // 加载所有产品列表
    getAllProductList().then((res) => {
        res.data.forEach((item) => {
            item.products.forEach((product) => {
                products.push(product);
            });
        });
    });
});

// 组件卸载时，移除粘贴事件监听器
onUnmounted(() => {
    window.removeEventListener('paste', handlePaste);
});

/* ******************************父组件传来的属性/方法****************************** */
// 接收父组件传递的属性，控制对话框的显示与隐藏
const addOrderUseOCRVisible = defineModel({ required: true, default: false });
// 接收父组件传递的客户信息
const props = defineProps<{
    customerInfo: {
        customerId: string;
        customerName: string;
        customerAbbreviation: string;
    };
}>();

/* ******************************通用属性/方法****************************** */
// 处理粘贴事件，支持粘贴图片和 PDF 文件  event - 剪贴板事件对象
const handlePaste = (event: ClipboardEvent) => {
    const clipboardData = event.clipboardData;
    if (clipboardData) {
        const items = clipboardData.items;
        for (let i = 0; i < items.length; i++) {
            const item = items[i];
            if (item.kind === 'file') {
                const blob = item.getAsFile();
                if (blob) {
                    if (blob.type.startsWith('image/')) {
                        // 存储图片文件
                        file.value = blob;
                        // 生成图片预览地址
                        previewImage.value = URL.createObjectURL(blob);
                        // 重置 PDF 页数
                        pdfPageCount.value = 0;
                        // 阻止默认粘贴行为
                        event.preventDefault();
                    } else if (blob.type === 'application/pdf') {
                        // 存储 PDF 文件
                        file.value = blob;
                        // 生成 PDF 预览地址
                        previewPDF.value = URL.createObjectURL(blob);
                        // 获取 PDF 页数
                        getPDFPageCount(blob);
                        // 阻止默认粘贴行为
                        event.preventDefault();
                    } else {
                        // 如果不是图片或 PDF 文件则提示
                        ElMessage.warning('粘贴的内容不是图片或 PDF，请重新复制后再粘贴');
                    }
                    break;
                }
            }
        }
    }
};

/* ******************************上传图片/pdf属性/方法****************************** */
// 图片预览地址
const previewImage = ref('');
// PDF 预览地址
const previewPDF = ref('');
// 文件输入框引用
const fileInput = ref<HTMLInputElement | null>(null);
// 存储图片或 PDF 文件
const file = ref<File | null>(null);
// 存储 PDF 页数
const pdfPageCount = ref(0);
// 加载动画
const ocrLoading = ref(false);

// 打开文件选择对话框
const openFileDialog = () => {
    fileInput.value?.click();
};
// 处理文件上传事件
const handleFileUpload = (event: Event) => {
    const target = event.target as HTMLInputElement;
    const selectedFile = target.files?.[0];
    if (selectedFile) {
        if (selectedFile.type.startsWith('image/')) {
            // 存储图片文件
            file.value = selectedFile;
            previewImage.value = URL.createObjectURL(selectedFile);
            previewPDF.value = '';
            // 重置 PDF 页数
            pdfPageCount.value = 0;
        } else if (selectedFile.type === 'application/pdf') {
            // 存储 PDF 文件
            file.value = selectedFile;
            previewPDF.value = URL.createObjectURL(selectedFile);
            previewImage.value = '';
            // 获取 PDF 页数
            getPDFPageCount(selectedFile);
        }
    }
    // 清空输入框，以便能重复选择同一文件
    target.value = '';
};
// 获取 PDF 文件的页数
const getPDFPageCount = async (pdfFile: File) => {
    try {
        const arrayBuffer = await pdfFile.arrayBuffer();
        const pdf = await pdfjs.getDocument({ data: arrayBuffer }).promise;
        pdfPageCount.value = pdf.numPages;
    } catch (error) {
        ElMessage.error('获取 PDF 页数失败');
        console.error('获取 PDF 页数失败:', error);
    }
};
// 将文件转换为 Base64 格式
const convertFileToBase64 = (file: File): Promise<string> => {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => {
            const base64String = reader.result as string;
            resolve(base64String.split(',')[1]); // 提取 Base64 数据部分
        };
        reader.onerror = reject;
        reader.readAsDataURL(file);
    });
};
// 清除预览信息
const clearPreview = () => {
    previewImage.value = '';
    previewPDF.value = '';
    file.value = null;
    // 重置 PDF 页数
    pdfPageCount.value = 0;
};
// 上传图片或 PDF 文件，调用 OCR 识别接口
const uploadImage = async () => {
    if (file.value && (previewImage.value || previewPDF.value)) {
        try {
            ocrLoading.value = true;
            // 将文件转换为 Base64 格式
            const base64File = await convertFileToBase64(file.value);

            // 分情况调用 getOCR 方法
            if (file.value.type.startsWith('image/')) {
                // 处理图片
                const result = await getOCR('image', base64File);
                ocrLoading.value = false;
                ocrResult.length = 0;
                ocrResult.push(...result.data);
            } else if (file.value.type === 'application/pdf') {
                // 处理 PDF
                const result = await getOCR('pdf', base64File, pdfPageCount.value);
                ocrLoading.value = false;
                ocrResult.length = 0;
                ocrResult.push(...result.data);
            }
        } finally {
            // 上传完成后清除预览
            ocrLoading.value = false;
            clearPreview();
        }
    }
};

/* ******************************table属性/方法****************************** */
const ocrResult = reactive<OcrData[]>([]);
// 根据表格单元格信息生成表格行数据 -- 接收表格单元格信息数组作为参数
const getRows = (body: OcrData['tables_result'][number]['body']) => {
    // 初始化一个数组 rows，用于存储表格的行数据，每个元素包含行起始索引、单元格数组和 DOM 行索引
    const rows: OpenPlatform['RowData'] = [];
    // 单元格所在的 DOM 行索引，初始值为 0
    let domRowIndex = 0;

    // 遍历表格每个单元格信息并生成行数据
    body.forEach((cell) => {
        // 计算单元格必须跨越的列数
        const colSpan = cell.col_end - cell.col_start;
        // 计算单元格必须跨越的行数
        const rowSpan = cell.row_end - cell.row_start;
        // 单元格唯一标识符
        const id = cell.row_start + '-' + cell.col_start;
        // 如果当前行不存在，初始化行数据
        if (!rows[cell.row_start]) {
            rows[cell.row_start] = {
                row_start: cell.row_start,
                row_end: cell.row_end,
                col_start: cell.col_start,
                col_end: cell.col_end,
                cells: [{ nanoid: id, rowSpan: rowSpan, colSpan: colSpan, selected: false, words: cell.words }],
                domRowIndex,
            };
            domRowIndex++;
        } else {
            // 如果当前行已经存在，更新行数据
            rows[cell.row_start].cells.push({
                nanoid: id,
                rowSpan: rowSpan,
                colSpan: colSpan,
                selected: false,
                words: cell.words,
            });
        }
    });
    // 删除空行
    return rows.filter((row) => row);
};

/* ******************************选中table属性/方法****************************** */
// 存储选中的表格数据
const selectedData = ref<{ nanoid: string; words: string }[]>([]);
// 记录框选开始的单元格位置
const startCell = ref<{ row: number; col: number } | null>(null);

// 开始框选操作，记录框选起始单元格的位置，并清空之前选中的数据。当用户在表格单元格上按下鼠标左键时，该函数会被触发，用于标记框选操作的起始位置。
const startSelection = (event: MouseEvent) => {
    // 将事件的目标元素强制转换为 HTML 表格单元格元素（<td>）
    const td = event.target as HTMLTableCellElement;
    // 获取当前单元格所在行的索引，通过访问其父节点（<tr>）的 rowIndex 属性得到
    const rowIndex = (td.parentNode as HTMLTableRowElement).rowIndex;
    // 获取当前单元格在所在行中的列索引
    const colIndex = td.cellIndex;
    // 将当前单元格的行索引和列索引作为起始位置，存储到 startCell 响应式变量中
    startCell.value = { row: rowIndex, col: colIndex };
    // 清空之前选中的数据，确保每次框选都是新的操作
    selectedData.value = [];
    selectedData.value.push({
        nanoid: td.dataset['nanoid'] as string,
        words: td.innerText,
    });
};

// 更新框选范围，获取选中的表格数据。当用户按住鼠标左键在表格单元格上移动时，该函数会被触发，动态更新选中的单元格范围。
const updateSelection = (event: MouseEvent) => {
    // 检查框选操作是否已经开始，即 startCell 是否有值
    if (startCell.value) {
        // 将事件的目标元素强制转换为 HTML 表格单元格元素（<td>）
        const td = event.target as HTMLTableCellElement; // 获取当前鼠标所在单元格所在行的索引，通过访问其父节点（<tr>）的 rowIndex 属性得到
        selectedData.value.push({
            nanoid: td.dataset['nanoid'] as string,
            words: td.innerText,
        });
    }
};
// 结束框选操作
const endSelection = () => {
    startCell.value = null;
};

/* ******************************处理选中的表格数据****************************** */
// 处理表格的加载动画
const createLoading = ref(false);
// 所有产品列表
const products = reactive<AjaxResponse['productList']>([]);
// 匹配产品数据
const matchProducts = (word: string) => {
    return products.find((i) => i.productName === word);
};
// 上传的订单产品名称数据
const uploadProductNameData = reactive<string[]>([]);
// 上传的订单产品数量数据
const uploadOrderNumberData = reactive<number[]>([]);
// 上传的订单不含税单价数据
const uploadExcludTaxPriceData = reactive<number[]>([]);
// 上传的订单含税单价数据
const uploadIncludeTaxPriceData = reactive<number[]>([]);

// 处理选中的表格数据
const processSelectedData = (type: 'productName' | 'orderNumber' | 'excludTaxPrice' | 'includeTaxPrice') => {
    // 没有选定内容
    if (selectedData.value.length == 0) {
        ElMessage.error('请先框选表格数据');
        return;
    }

    switch (type) {
        case 'productName':
            uploadProductNameData.length = 0;
            for (let index = 0; index < selectedData.value.length; index++) {
                const selected = selectedData.value[index];
                if (matchProducts(selected.words)) {
                    uploadProductNameData.push(selected.words);
                }
            }
            if (uploadProductNameData.length == 0) {
                ElMessage.error('未匹配到产品名称');
                return;
            }
            ElMessage.success(`匹配到${uploadProductNameData.length}条产品名称`);
            break;
        case 'orderNumber':
            uploadOrderNumberData.length = 0;
            for (let index = 0; index < selectedData.value.length; index++) {
                const selected = selectedData.value[index];
                uploadOrderNumberData.push(Number(selected.words));
            }
            if (uploadOrderNumberData.length == 0) {
                ElMessage.error('未匹配到产品数量');
                return;
            }

            // 如果不是number类型则提示错误
            if (uploadOrderNumberData.some((i) => isNaN(i))) {
                ElMessage.error('产品数量必须为数字');
                uploadOrderNumberData.length = 0;
                return;
            }
            ElMessage.success(`匹配到${uploadProductNameData.length}条产品数量`);
            break;
        case 'excludTaxPrice':
            uploadExcludTaxPriceData.length = 0;
            for (let index = 0; index < selectedData.value.length; index++) {
                const selected = selectedData.value[index];
                uploadExcludTaxPriceData.push(Number(selected.words));
            }

            if (uploadExcludTaxPriceData.length == 0) {
                ElMessage.error('未匹配到不含税单价');
                return;
            }

            if (uploadIncludeTaxPriceData.length !== 0) {
                uploadIncludeTaxPriceData.length = 0;
                ElMessage.warning('已设置含税单价，本次设置不含税单价将覆盖含税单价');
            } else {
                ElMessage.success(`设置不含税价成功`);
            }
            break;
        case 'includeTaxPrice':
            uploadIncludeTaxPriceData.length = 0;
            for (let index = 0; index < selectedData.value.length; index++) {
                const selected = selectedData.value[index];
                uploadIncludeTaxPriceData.push(Number(selected.words));
            }

            if (uploadIncludeTaxPriceData.length == 0) {
                ElMessage.error('未匹配到含税单价');
                return;
            }

            if (uploadExcludTaxPriceData.length !== 0) {
                uploadExcludTaxPriceData.length = 0;
                ElMessage.warning('已设置不含税单价，本次设置含税单价将覆盖不含税单价');
            } else {
                ElMessage.success(`设置含税单价成功`);
            }
            break;
        default:
            break;
    }
};

/* ******************************创建订单属性/方法****************************** */
// 订单号
const orderNo = ref('');
const instance = getCurrentInstance();
// 创建订单事件
const createOrderEvent = () => {
    if (orderNo.value == '') {
        ElMessage.error('请输入订单号');
        return;
    }

    if (uploadProductNameData.length == 0) {
        ElMessage.error('请选择产品');
        return;
    }

    if (uploadOrderNumberData.length == 0) {
        ElMessage.error('请选择产品数量');
        return;
    }

    if (uploadExcludTaxPriceData.length == 0 && uploadIncludeTaxPriceData.length == 0) {
        ElMessage.error('请设置含税单价或不含税单价');
        return;
    }

    // 计算价格
    if (uploadIncludeTaxPriceData.length !== 0) {
        // 含税价
        const orderData: AjaxRequest['addOrderUseSystemForm'] = {
            customerId: props.customerInfo.customerId,
            customerName: props.customerInfo.customerName,
            orderDate: new Date(),
            orderNo: orderNo.value,
            orderDeliveryDate: '暂无送货计划',
            orderRemark: '',
            orderTax: true,
            orderAmount: 0,
            orderDetail: uploadProductNameData.map((i, index) => {
                const product = matchProducts(i);
                return {
                    productId: product!._id,
                    materialNumber: product!.materialNumber,
                    productName: product!.productName,
                    productSize: product!.productSize,
                    orderNumber: uploadOrderNumberData[index],
                    excludTaxPrice: Number((uploadIncludeTaxPriceData[index] / 1.13).toFixed(2)),
                    includeTaxPrice: uploadIncludeTaxPriceData[index],
                    subtotal: Number((uploadIncludeTaxPriceData[index] * uploadOrderNumberData[index]).toFixed(2)),
                    remark: '',
                };
            }),
            creator: useUserStore().username,
            creatorId: useUserStore().id,
        };

        // 总价
        orderData.orderAmount = orderData.orderDetail.reduce((pre, cur) => pre + cur.subtotal, 0);
        createOrder(orderData).then((res) => {
            if (res.code == 200) {
                ElMessage.success('创建订单成功');
                orderNo.value = '';
                uploadProductNameData.length = 0;
                uploadOrderNumberData.length = 0;
                uploadExcludTaxPriceData.length = 0;
                uploadIncludeTaxPriceData.length = 0;
                instance?.proxy?.$Bus.emit('updateOrderList');
                addOrderUseOCRVisible.value = false;
            }
        });
    } else {
        // 不含税价
        const orderData: AjaxRequest['addOrderUseSystemForm'] = {
            customerId: props.customerInfo.customerId,
            customerName: props.customerInfo.customerName,
            orderDate: new Date(),
            orderNo: orderNo.value,
            orderDeliveryDate: '暂无送货计划',
            orderRemark: '',
            orderTax: false,
            orderAmount: 0,
            orderDetail: uploadProductNameData.map((i, index) => {
                const product = matchProducts(i);
                return {
                    productId: product!._id,
                    materialNumber: product!.materialNumber,
                    productName: product!.productName,
                    productSize: product!.productSize,
                    orderNumber: uploadOrderNumberData[index],
                    excludTaxPrice: uploadExcludTaxPriceData[index],
                    includeTaxPrice: Number((uploadExcludTaxPriceData[index] * 1.13).toFixed(2)),
                    subtotal: Number((uploadExcludTaxPriceData[index] * uploadOrderNumberData[index]).toFixed(2)),
                    remark: '',
                };
            }),
            creator: useUserStore().username,
            creatorId: useUserStore().id,
        };

        // 总价
        orderData.orderAmount = orderData.orderDetail.reduce((pre, cur) => pre + cur.subtotal, 0);
        createOrder(orderData).then((res) => {
            if (res.code == 200) {
                ElMessage.success('创建订单成功');
                orderNo.value = '';
                uploadProductNameData.length = 0;
                uploadOrderNumberData.length = 0;
                uploadExcludTaxPriceData.length = 0;
                uploadIncludeTaxPriceData.length = 0;
                instance?.proxy?.$Bus.emit('updateOrderList');
                addOrderUseOCRVisible.value = false;
            }
        });
    }
};
</script>

<style scoped lang="scss">
// 粘贴区域样式
.paste-area {
    border: 2px dashed #d9d9d9;
    border-radius: 8px;
    padding: 20px;
    text-align: center;
    min-height: 200px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;

    // 粘贴提示文字样式
    .paste-tip {
        color: #666;
        font-size: 16px;
        margin-bottom: 10px;
    }

    // 预览容器样式
    .preview-container {
        margin-top: 20px;

        // 图片预览样式
        .preview-image {
            max-width: 100%;
            max-height: 200px;
            margin-bottom: 10px;
            border-radius: 4px;
        }

        // PDF 页数显示样式
        .pdf-page-count {
            color: #666;
            font-size: 14px;
            margin-top: 10px;
        }
    }
}

// 选择区域
.show-selected-area {
    border: 2px dashed #d9d9d9;
    border-radius: 8px;
    margin: 20px 0;
    padding: 5px;
    text-align: center;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    table {
        width: 100%;
        border-collapse: collapse;
        th,
        td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
            user-select: none;
        }
    }
}

// 识别区域
.ocr-area {
    // 表格内容区域样式
    .table-content {
        margin-top: 20px;

        // 表格样式
        table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 20px;

            // 表格表头和单元格样式
            th,
            td {
                border: 1px solid #ddd;
                padding: 8px;
                text-align: left;
                user-select: none;
            }

            // 表格表头样式
            th {
                background-color: #f2f2f2;
            }

            // 选中单元格样式
            .selected-cell {
                background-color: #e6f7ff; /* 选中单元格背景色 */
                border: 1px solid #1890ff; /* 选中单元格边框颜色 */
            }
        }
    }
    // 选中表格区域展示
}

// 自定义头部样式
.my-header {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    gap: 16px;
}

// 表格操作选项区域样式
.table-options {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
}
</style>
